#ifndef __BHTTP_CLIENT_IMPL_H__
#define __BHTTP_CLIENT_IMPL_H__
#pragma once

#include <string>
#include <vector>
#include <curl/curl.h>
#include "thread.h"
#include "request.h"
#include "response.h"

namespace bhttp
{
class client_impl
{
    friend class client;
public:
    explicit client_impl(const std::string& host, int timeout = 3, const std::string& ca = std::string());
    ~client_impl();

    /**
     * @brief timeout 设置连接超时时间
     * @param secs 时间值(秒)
     * @return void
     */
    void timeout(int secs);

    /**
     * @brief capath 设置CA证书路径
     * @param ca 证书路径
     * @return void
     */
    void capath(const std::string& ca);

    /**
     * @brief host 设定服务器地址
     * @param host 服务器地址
     * @return void
     */
    void host(const std::string& host);

    /**
     * @brief process 异步处理请求
     * @param req 请求参数
     * @param res_cb 结果回调函数
     * @return void
     */
    void process(const std::shared_ptr<request>& req, const std::function<void(const std::shared_ptr<request>&, const std::shared_ptr<response>&)>& res_cb);
private:
    /**
     * @brief init_options 设置选项
     * @return true=成功，否则失败
     */
    bool init_options();

    /**
     * @brief init_params 设置参数
     * @param req 请求数据
     * @param rep 回复数据
     * @return true=成功，否则失败
     */
    bool init_params(const std::shared_ptr<request>& req, std::shared_ptr<response>& rep);

    /**
     * @brief perform 执行请求
     * @param rep 回复数据
     * @return true=成功
     */
    bool perform(std::shared_ptr<response>& rep);

    /**
     * @brief get GET请求
     * @param req 请求数据
     * @param rep 回复数据
     * @return void
     */
    void get(const std::shared_ptr<request>& req, std::shared_ptr<response>& rep);

    /**
     * @brief get GET请求
     * @param req 请求数据
     * @param rep 回复数据
     * @return void
     */
    void post(const std::shared_ptr<request>& req, std::shared_ptr<response>& rep);

    /**
     * @brief get GET请求
     * @param req 请求数据
     * @param rep 回复数据
     * @return void
     */
    void del(const std::shared_ptr<request>& req, std::shared_ptr<response>& rep);

    /**
     * @brief get GET请求
     * @param req 请求数据
     * @param rep 回复数据
     * @return void
     */
    void put(const std::shared_ptr<request>& req, std::shared_ptr<response>& rep);

    /**
     * @brief get GET请求
     * @param req 请求数据
     * @param rep 回复数据
     * @return void
     */
    void patch(const std::shared_ptr<request>& req, std::shared_ptr<response>& rep);

    /**
     * @brief setopt 设置参数
     * @param option 设置选项
     * @param data 模板数据
     * @return CURLcode
     */
    template<typename T>
    inline CURLcode setopt(CURLoption option, T data)
    {
        CURLcode code = curl_easy_setopt(curl_, option, data);
        if (CURLE_OK != code)
        {
            const curl_easyoption* opt = curl_easy_option_by_id(option);
            std::string str;
            if (opt) str = opt->name;
            fprintf(stderr, "Option[%s] Error: %s\n", str.c_str(), curl_easy_strerror(code));
        }
        return code;
    }

private:
    // 连接超时时间(秒)
    int timeout_{ 10 };
    // ca证书路径
    std::string capath_;
    // 服务器地址
    std::string host_;
    // CURL句柄
    CURL* curl_{ nullptr };
    // 请求头
    curl_slist* hds_{ nullptr };
    // 处理线程
    std::unique_ptr<thread> thd_;
};
}

#endif //__BHTTP_CLIENT_IMPL_H__
